--#include "data\config\boss\CommonBossConfig.lua" once
----#include "data\functions\CommonFunc.lua" once
--#include "data\functions\Boss\BossBattleField.lua" once   --BOSS战场
--#include "data\functions\Fuben\KongFuMaster.lua" once     --练功师
--#include "data\functions\MonEvent\MonsterMobDispatchImpl.lua" once
--#include "data\functions\MonEvent\MonsterLiveTimeOutDispatchImpl.lua" once 
--#include "data\functions\MonEvent\MDCDispatcherImplement.lua" once
--#include "data\functions\Boss\BossWanted.lua" once       --BOSS悬赏

--CommonBossKilledTime = {}				--公共BOSS被击杀的时间
GatherMonsterDispatcher = {}  			--怪物是否能采集的回调

GatherMonsterDispatcher.register = function(nMonsterId, proc )
	if not proc then
		print("GatherMonsterDispatcher Register Error, nMonsterId["..nMonsterId.."]，proc is nil")
	end
	local monsterEntityType = System.getMonsterEntityTypeById(nMonsterId)
    if monsterEntityType ~= enGatherMonster then
    	print("GatherMonsterDispatcher Register Error, nMonsterId["..nMonsterId.."],MonsterType:"..monsterEntityType)
    end
	local callTable = GatherMonsterDispatcher[nMonsterId]
	if not callTable or type(callTable) ~= "table" then
    	GatherMonsterDispatcher[nMonsterId] = {}
    	System.registerMonsterGather(nMonsterId, true)
    else
    	for i,v in ipairs( callTable ) do
    		if callTable[i] == proc then
        		return
      		end
    	end
    end
    table.insert( GatherMonsterDispatcher[nMonsterId], proc )
end

GatherMonsterDispatcher.dispatch = function( sysarg, pMonster, nMonsterId ) 
	local callTable = GatherMonsterDispatcher[nMonsterId]
	if callTable then
		for i, gatherMonsterCallProc in ipairs( callTable ) do
			if not gatherMonsterCallProc( sysarg,  pMonster, nMonsterId) then
				return false
			end
		end
		return true
	end
	return false
end

--[[下发已刷出的BOSS的]]
function SendAllAliveBoss( sysarg )
	local bossTable = {}
	for idx, group in ipairs( AliveBossPanelConfig ) do
		for i, oneBoss in ipairs( group.groupBoss ) do
			local num = System.getMonsterCountById( oneBoss.bossId, oneBoss.sceneId, 0 )
			if num > 0 then				--已刷出
				table.insert( bossTable, {oneBoss.bossId, oneBoss.sceneId} )
			end
		end
	end

	if not bossTable then
		return
	end

	local npack = DataPack.allocPacket(sysarg, enBossSystemID, sSendAllAliveBoss)
	if npack then
		local num = #bossTable
		DataPack.writeShort(npack, num)
		--print("SendAllAliveBoss, num="..num)
		for i, oneBoss in ipairs( bossTable ) do
			DataPack.writeShort(npack, oneBoss[1])
			DataPack.writeShort(npack, oneBoss[2])
			--print("SendAllAliveBoss  , bossId="..oneBoss[1]..", sceneId="..oneBoss[2])
		end
		DataPack.flush(npack)
	end
end

--[[下发已刷出的BOSS的]]
function SendAwardBossData( sysarg )
	--print("SendAwardBossData...")
	local awardBossList = {}
	for bossId, bossCfg in pairs( MobBossCommonConfig ) do
		if bossCfg.awardMonsterId and bossCfg.awardMonsterId > 0 and bossCfg.awardKillNum and bossCfg.awardKillNum > 0 then
			table.insert( awardBossList, { bossCfg.monsterId, bossCfg.awardMonsterId, bossCfg.awardKillNum, bossCfg.sceneId } )
		end
	end

	local npack = DataPack.allocPacket(sysarg, enBossSystemID, sAwardBossSendData)
	if npack then
		DataPack.writeByte(npack, #awardBossList)
		for i, awardBoss  in ipairs( awardBossList ) do
			local awardBossId 	= awardBoss[2]
			local killBossId 	= awardBoss[1]
			local sche 			= GetAwardKillNum(killBossId) or 0
			local scheMax 		= awardBoss[3]
			local sceneId 		= awardBoss[4]
			local num 			= System.getMonsterCountById( awardBossId, sceneId, 0 )
			local awardBossSts  = 0
			if num > 0 then
				awardBossSts = 1
			end

			DataPack.writeShort(npack, awardBossId)
			DataPack.writeShort(npack, killBossId)
			DataPack.writeShort(npack, sche)
			DataPack.writeShort(npack, scheMax)
			DataPack.writeByte(npack, awardBossSts)
			--print("SendAwardBossData, awardBossId="..awardBossId..", killBossId="..killBossId..", sche="..sche..", scheMax="..scheMax..", sts="..awardBossSts)
		end
		DataPack.flush(npack)
	end
end

--[[
获取某场景BOSS的剩余复活时间
只适用于有墓碑怪，并且BOSS与墓碑怪一一对应的情况
返回值：
-1：无法找到剩余复活时间
0： 已经刷出
>0:剩余复活时间
]]
function GetSceneBossReliveTime( sceneId, fubenHandle, bossId )
	local num = System.getMonsterCountById( bossId, sceneId, fubenHandle ) or 0
	if num > 0 then
		return 0
	end
	local hScene = Fuben.getSceneHandleById( sceneId, fubenHandle )
	local bossPtr = Fuben.getMonsterPtrById( hScene, bossId )
	if not bossPtr then
		return -1
	end

	local reliveTime = Actor.getIntProperty(bossPtr, PROP_MONSTER_LIVE_TIMEOUT)
	return reliveTime
end

function SendOneAliveBoss( sysarg, bossId, sceneId )
	local npack = DataPack.allocPacket(sysarg, enBossSystemID, sSendAllAliveBoss)
	if npack then
		DataPack.writeShort(npack, 1)
		--print("SendOneAliveBoss, num="..num)
		for i, oneBoss in ipairs( bossTable ) do
			DataPack.writeShort(npack, bossId)
			DataPack.writeShort(npack, sceneId)
			print("SendOneAliveBoss  , bossId="..bossId..", sceneId="..sceneId)
		end
		DataPack.flush(npack)
	end
end

--[[
获取BOSS状态
0-配置不存在或无意义，、1-未刷出、2-进行中（已刷出）、3-已击杀
]]
function GetCommonBossSceneStatus( bossId )
	local bossCfg = MobBossCommonConfig[bossId]
	if not bossCfg then
		return 0
	end

	if not bossCfg.recStatus then
		return 0
	end

	local dVar = System.getDyanmicVar()
	if not dVar.commonBossSceneSts then
		dVar.commonBossSceneSts = {}
	end

	local num = System.getMonsterCountById( bossCfg.monsterId, bossCfg.sceneId, 0 )
	if num > 0 then
		return 2 			--BOSS进行中（已刷出）
	end
	local bossSts = dVar.commonBossSceneSts[bossId] or 1
	return bossSts
end

--[[
获取BOSS状态
	1-未刷出、3-已击杀
]]
function SetCommonBossSceneStatus( bossId, newSts )
	local bossCfg = MobBossCommonConfig[bossId]
	if not bossCfg then
		return
	end

	if not bossCfg.recStatus then		--需要记录BOSS状态
		return
	end

	local dVar = System.getDyanmicVar()
	if not dVar.commonBossSceneSts then
		dVar.commonBossSceneSts = {}
	end

	dVar.commonBossSceneSts[bossId] = newSts
end


--[[
传送到场景BOSS
payFlag:是否付费，0-免费传送，1-付费传送，扣除货币或者道具
]]
function TelToSceneBoss( sysarg, bossId, payFlag )
	local bossCfg = GetAliveBossPanelCfgByBossId( bossId )
	if not bossCfg then
		return
	end

	local num = System.getMonsterCountById( bossCfg.bossId, bossCfg.sceneId, 0 )
	if num < 1 then 			--BOSS尚未刷出，不能速传
		Actor.sendTipmsg(sysarg, Lang.ScriptTips.COM0029,ttFlyTip)
		return
	end

	CommonTeleportByTeleId( sysarg, bossCfg.teleId )
end

function GetAliveBossPanelCfgByBossId( bossId )
	for idx, group in ipairs( AliveBossPanelConfig ) do
		for i, oneBoss in ipairs( group.groupBoss ) do
			if oneBoss.bossId == bossId then
				return oneBoss
			end
		end
	end
	return nil
end

--[[
引擎启动时刷出MobBossCommonConfig中配置的BOSS
]]
function FreshCommonBossWhenStart( )
	local hasCond = {}
	hasCond.openDays = System.getDaysSinceOpenServer()
	hasCond.combDays = System.getDaysSinceCombineServer()
	for bossId, bossCfg in pairs( MobBossCommonConfig ) do
		--print("FreshCommonBossWhenStart, bossId="..bossId)
		if bossCfg.startMob and CheckCommomBossMobCond( bossCfg, hasCond )  then	 	--允许启动时刷出，且条件满足
			if bossCfg.pos then
				freshSceneMonsterInPos( bossCfg )
			elseif bossCfg.range then
				freshSceneMonsterInRange( bossCfg )
			end
		end
	end
end


--[[
在线跨天时刷BOSS
startMob：为false的，不自动刷出
]]
function FreshCommonBossWhenNewDay()
	local hasCond = {}
	hasCond.openDays = System.getDaysSinceOpenServer()
	hasCond.combDays = System.getDaysSinceCombineServer()
	for bossId, bossCfg in pairs( MobBossCommonConfig ) do
		--print("FreshCommonBossWhenStart, bossId="..bossId)
		if  bossCfg.newDayMob and CheckCommomBossMobCond( bossCfg, hasCond ) then 	--允许跨天时刷出，且条件满足
			if bossCfg.pos then
				freshSceneMonsterInPos( bossCfg )
			elseif bossCfg.range then
				freshSceneMonsterInRange( bossCfg )
			end
		end
	end
end

--[[
每天0点处理
]]
function CommonBossDailyProc()
	FreshCommonBossWhenNewDay()
end

--[[
检查mob条件
1、开服、合服天数要求
2、是否存其墓碑怪
]]
function CheckCommomBossMobCond( bossCfg, hasCond )
	--开服天数不满足要求，并且合服天数不满足要求
	local openDayLimit = true
	if bossCfg.mobDayLimit and bossCfg.mobDayLimit.openDay and hasCond.openDays < bossCfg.mobDayLimit.openDay then 	--有开服天数要求
		--print("--->CheckCommomBossMobCond, hasCond.openDays="..hasCond.openDays..", mobDayLimit.openDay="..bossCfg.mobDayLimit.openDay)
		openDayLimit = false
	end

	local combDayLimit = true
	if bossCfg.mobDayLimit and bossCfg.mobDayLimit.combDay and hasCond.combDays < bossCfg.mobDayLimit.combDay then 	--有合服天数要求
		--print("--->CheckCommomBossMobCond, hasCond.combDays="..hasCond.combDays..", mobDayLimit.combDay="..bossCfg.mobDayLimit.combDay)
		combDayLimit = false
	end

	if not openDayLimit and not combDayLimit then
		--print("--->CheckCommomBossMobCond, mob false")
		return false
	end

	--已经有BOSS
	local num1 = System.getMonsterCountById( bossCfg.monsterId, bossCfg.sceneId, 0 )
	if num1 > 0 then
		return false
	end

	--已经有了墓碑怪（则走墓碑怪到期刷BOSS功能）
	if bossCfg.deadMonsterId then
		local num2 = System.getMonsterCountById( bossCfg.deadMonsterId, bossCfg.sceneId, 0 )
		if num2 > 0 then
			return false
		end
	end

	return true
end


--BOSS mob 处理
function OnCommonBossMob(monster, monId, sceneId, x, y)
	--print("OnCommonBossMob, monId="..monId..", sceneId="..sceneId..", x="..x..", y="..y)	--定位问题用，完成后去掉
	BroadCommonBossMobMsg( monster, monId )
	--KillCommonDeadMonster( monId )
end

--BOSS die 处理
function OnCommonBossDie(monster, Killer, monId, lastHitKiller)
	--print("OnCommonBossDie, monId="..monId)				--定位问题用，完成后去掉
	AddBossScoreByKillBoss( monster, Killer, monId )
	BroadCommonBossKillMsg( monster, Killer, monId, lastHitKiller )

	OnBossWantedBeKilled( lastHitKiller, monId )			
end

--boss刷新时间根据在线人数
function GetRevivalTimeRate()
	local playerList = LuaHelp.getAllActorList() or {}
	local count = #playerList
	for i=#(BossRevivalTimeRateConfig),1, -1 do
		if count > BossRevivalTimeRateConfig[i].onlinePlayerCount then
			return BossRevivalTimeRateConfig[i].timeRate
		end
	end
	return 1
end


function GetBossRevivalCd(bossId, revivalCds)
	if not revivalCds then
		return 0
	end
	local openday = System.getDaysSinceOpenServer()
	local revivalCd = revivalCds[openday]
	if not revivalCd then
		revivalCd = revivalCds[#revivalCds] or 0
	end
	local killTime,revivalTimeRate = GetCommonBossKilledTime( bossId )
	revivalCd = math.floor(revivalCd * revivalTimeRate)
	
	return revivalCd
end

--[[
怪物被击杀，如果有，则mob出一个deadMonsterId的怪
]]
function MobCommonDeadMonster( monster, monId )
	--print("MobCommonDeadMonster, monId="..monId)
	local bossCfg = MobBossCommonConfig[monId]
	if not bossCfg then
		return
	end

	if bossCfg.deadMonsterId and bossCfg.deadMonsterId > 0 then
		local deadBossCfg = {}
		deadBossCfg.monsterId 	= 	bossCfg.deadMonsterId
		deadBossCfg.sceneId		=	bossCfg.sceneId
		deadBossCfg.livetime 	=	GetBossRevivalCd(monId, bossCfg.revivalCd )	--墓碑怪的生命周期就是主怪的复活周期
		deadBossCfg.num			=	bossCfg.num
		deadBossCfg.pos 		=	bossCfg.pos
		--freshSceneMonsterInPos( deadBossCfg )				--刷出一个墓碑怪
		local monster = freshSceneOneMonsterInPos( deadBossCfg, 0 )
		if monster then
			Actor.setOtherMonsterId( monster, monId ) 		--刷墓碑怪成功
		else
			--刷墓碑怪失败
			System.sendCommonLog( GameLog.clCommonBossRefreshFail, monId, "" , 0, monId, bossCfg.deadMonsterId, '', 'dead boss fail', '' )
		end
	end
end

--[[
清除主怪的deadmonster
]]
function KillCommonDeadMonster( monId )
	local bossCfg = MobBossCommonConfig[monId]
	if not bossCfg then
		return
	end

	if bossCfg.deadMonsterId and bossCfg.deadMonsterId > 0 then
		local deadBossCfg = {}
		deadBossCfg.monsterId 	= 	bossCfg.deadMonsterId
		deadBossCfg.sceneId 	=	bossCfg.sceneId
		clearScenceMonster( deadBossCfg, 0 )
	end
end

--[[
处理BOSS的复活，注册定时器
1、如果BOSS配置有对应的awardKillNum和awardMonsterId，则当击杀次数达到时，mob出一个额外奖励的awardMonster
2、BOSS的击杀、复活流程不变；
]]
function ProcCommonBossRevival(monster, monId)
	--print("ProcCommonBossRevival, monId="..monId)
	local bossCfg = MobBossCommonConfig[monId]
	if not bossCfg then
		return
	end

	--[[
	如果BOSS配置有对应的awardKillNum和awardMonsterId，则当击杀次数达到时，mob出一个额外奖励的awardMonster
	]]
	if bossCfg.awardMonsterId and bossCfg.awardMonsterId > 0 and bossCfg.awardKillNum and bossCfg.awardKillNum > 0 then
		local awardKillNum 		= GetAwardKillNum( monId ) or 0
		local newAwardKillNum	= awardKillNum + 1
		SetAwardKillNum( monId, newAwardKillNum )			--击杀次数加1
		--print("ProcCommonBossRevival, monId="..monId..", newAwardKillNum="..newAwardKillNum)
		if newAwardKillNum >= bossCfg.awardKillNum then
			local awardBossCfg = MobBossCommonConfig[bossCfg.awardMonsterId] 		--击杀次数足够，mob出awardMonster
			if awardBossCfg then
				SetAwardKillNum( monId, 0 )				--原BOSS的奖励击杀次数清0,
				FreshCommonMonsters( { awardBossCfg }, 0, false )
			end
		end
	end

	--[[
	--如果需要检测复活条件，并且条件不满足，则不能设置复活
	if bossCfg.checkReliveCondFunc and not bossCfg.checkReliveCondFunc( monId ) then
		return
	end

	local revivalCd = GetBossRevivalCd( bossCfg.revivalCd )
	if revivalCd and revivalCd > 0 then			--有revivalCd，且revivalCd>0，该BOSS才会自动复活
		local NpcPtr = System.getGlobalNpc()
		Actor.regScriptTimer(NpcPtr, 0, revivalCd*1000, revivalCd*1000, 1, "OnCommonCreateBoss", bossCfg.monsterId )
		print("ProcCommonBossRevival, monId="..monId..", revivalCd="..revivalCd) 		--定位问题用
	end
	]]
end

function GetAwardKillNum( monId )
	--print("GetAwardKillNum, monId="..monId)
	local sVar = System.getStaticVar()
	if not sVar.awardBossKillNum then
		sVar.awardBossKillNum = {}
	end
	return sVar.awardBossKillNum[monId] or 0
end

function SetAwardKillNum( monId, newNum )
	--print("SetAwardKillNum, monId="..monId..", newNum="..newNum)
	local sVar = System.getStaticVar()
	if not sVar.awardBossKillNum then
		sVar.awardBossKillNum = {}
	end
	sVar.awardBossKillNum[monId] = newNum
end

--[[
创建BOSS
必须在MobBossCommonConfig配置（不再使用）
]]
function OnCommonCreateBoss( npcobj, bossId )
	bossId = tonumber(bossId)
	print("OnCommonCreateBoss, bossId="..bossId)			--定位问题用，完成后去掉
	local bossCfg = MobBossCommonConfig[bossId]
	if bossCfg then
		--如果需要检测mob条件，并且条件不满足，则不能设置刷出
		if bossCfg.checkMobCondFunc and not bossCfg.checkMobCondFunc( bossId ) then
			return
		end

		freshSceneMonsterInPos( bossCfg )

		local num = System.getMonsterCountById( bossCfg.monsterId, bossCfg.sceneId, 0 )
		if num <= 0 then		--因为某些原因没刷出来,1分钟后重刷1次
			local NpcPtr = System.getGlobalNpc()
			Actor.regScriptTimer(NpcPtr, 0, 60*1000, 60*1000, 1, "OnCommonCreateBossDelay", bossCfg.monsterId )
			print("OnCommonCreateBoss, delay 60 seconds, bossId="..bossId)			--定位问题用，完成后去掉
		end
	end
end

--[[
创建BOSS
必须在MobBossCommonConfig配置（不再使用）
]]
function OnCommonCreateBossDelay( npcobj, bossId )
	bossId = tonumber(bossId)
	print("OnCommonCreateBossDelay, bossId="..bossId)			--定位问题用，完成后去掉
	local bossCfg = MobBossCommonConfig[bossId]
	if bossCfg then
		freshSceneMonsterInPos( bossCfg )
	end
end

--[[
设置检测复活的方法
]]
function CommonBossSetCheckReliveFunc( bossId, bossReliveCondFunc )
	local bossCfg = MobBossCommonConfig[bossId]
	if not bossCfg then
		return
	end
	--print("CommonBossSetCheckReliveFunc, bossId="..bossId)
	bossCfg.checkReliveCondFunc = bossReliveCondFunc
end

--[[
设置检测Mob的方法
]]
function CommonBossSetCheckMobFunc( bossId, bossMobCondFunc )
	local bossCfg = MobBossCommonConfig[bossId]
	if not bossCfg then
		return
	end
	--print("CommonBossSetCheckMobFunc, bossId="..bossId)
	bossCfg.checkMobCondFunc = bossMobCondFunc
end

--[[
击杀BOSS获取积分
]]
function AddBossScoreByKillBoss( monster, Killer, monId )
	local bossCfg = BossScoreConfig[monId]
	if not bossCfg then
		return
	end
	--print(" AddBossScoreByKillBoss,  monId="..monId..", Score="..bossCfg.Score)
	--根据归属和队伍及衰减规则计算积分
	if Killer and bossCfg.Score > 0 then
		local monName = MonsterNameDeleteNumber( monId )
	    local teamId = Actor.getTeamId(Killer)
	    --print(" AddBossScoreByKillBoss,  teamId="..teamId)
		if teamId > 0 then
		    local nCount = 0
		    local playerList = LuaHelp.getTeamMemberList(Killer)
	        for i, player in ipairs(playerList or {}) do
			    if player then
			        if Actor.isInSameScreen(Killer,player) then
					    nCount = nCount + 1
					end
			    end
			end
			if nCount == 0 then
			    nCount = 1
			end
			local score  =  math.floor( bossCfg.Score / nCount )
	        for i, player in ipairs( playerList or {} ) do
			    if player then
			        if Actor.isInSameScreen(Killer,player) then						--要与击杀者同屏
					    local rate 			= GetBossScoreRate( player, monster )
						local playerScore 	= math.floor( score * rate )
						if playerScore > 0 then
						    --local  bossScore  = Actor.getIntProperty(player,PROP_ACTOR_BOSS_SCORE)
				            --Actor.setUIntProperty(player, PROP_ACTOR_BOSS_SCORE, bossScore + playerScore)
				            GiveCommonAward( player, { {type=qatBossScore, id=0, count=playerScore} }, 0, "" )		--走统一接口
				            Actor.sendTipmsg(player, string.format(Lang.ScriptTips.boss003, monName, playerScore), ttFlyTip+ttChatWindow)
                        else
						    --Actor.sendTipmsg(player,Lang.Script.Boss015,ttFlyTip)	
						end
					end
			    end
			end 	
		else
		    local rate 	= GetBossScoreRate(Killer,monster)
			local score = math.floor(bossCfg.Score * rate)
			if score  > 0 then
			    --local  bossScore  	= Actor.getIntProperty(Killer,  PROP_ACTOR_BOSS_SCORE)
				--Actor.setUIntProperty(Killer, PROP_ACTOR_BOSS_SCORE, bossScore + score)
				--local  allScore  	= Actor.getIntProperty(Killer,  PROP_ACTOR_BOSS_SCORE)
				--print("GetBossScoreRate, rate="..rate..", score="..score..", allScore="..allScore)
				GiveCommonAward( Killer, { {type=qatBossScore, id=0, count=score} }, 0, "" )		--走统一接口
				Actor.sendTipmsg(Killer, string.format(Lang.ScriptTips.boss003, monName, score), ttFlyTip+ttChatWindow)	
			else
			    --Actor.sendTipmsg(Killer,Lang.Script.Boss015,ttFlyTip)
			end
		end
	end
end

--[[获取BOSS积分衰减比率
]]
function GetBossScoreRate( playerPtr, bossPtr )
    local actorLevel 	=  Actor.getIntProperty(playerPtr,PROP_CREATURE_LEVEL)
	local bossLevel 	=  Actor.getIntProperty(bossPtr,PROP_CREATURE_LEVEL)
    local rate = System.getFunctionRuleRate( enFunctionRuleType_BossScore, 1, actorLevel-bossLevel)
    --print("GetBossScoreRate, rate="..rate)
    return rate
end

--[[
按BOSSID刷出BOSS
]]
function FreshCommonBossByBossId( bossId )
    local bossCfg = MobBossCommonConfig[bossId]
    if bossCfg then
		freshSceneMonsterInPos( bossCfg )
	end
end

--[[
通用刷BOSS*N，有则不刷
bossIds =	{ 261, 262, 263, 264, 265, 266, 267, 268,},
]]
function FreshCommonBossById( bossIds )
	for bossIdx, bossId in ipairs( bossIds ) do
		local bossCfg = MobBossCommonConfig[bossId]
		--print("FreshCommonBossById, bossId="..bossId)
		if bossCfg then
			freshSceneMonsterInPos( bossCfg )
		end
	end
end

--[[
刷新怪物、BOSS
]]
function FreshCommonMonsters( monsters, fubenHandle, bForce )
	for monIdx, oneMon in ipairs( monsters ) do
		if oneMon.pos then
			if bForce then
				freshSceneMonsterInPosForce( oneMon, fubenHandle )
			else
				freshSceneMonsterInPos( oneMon, fubenHandle )
			end
		elseif oneMon.range then
			if bForce then
				freshSceneMonsterInRangeForce( oneMon, fubenHandle )
			else
				freshSceneMonsterInRange( oneMon, fubenHandle )
			end
		end
	end
end


--[[
从指定N条怪物中随机X条刷出
]]
function FreshCommonMonstersRand( monsters, fubenHandle, bForce, randNum )
	--print("FreshCommonMonstersRand, randNum="..randNum)
	local monstersCopy = DeepCopyFromObject( monsters )   	--深度拷贝一个副本（不影响原始配置）
	local monstersNeedFresh = DistributeElem( monstersCopy, randNum, false )
	for monIdx, oneMon in ipairs( monstersNeedFresh ) do
	--for monIdx, oneMon in pairs(monstersNeedFresh) do
		--print("FreshCommonMonstersRand k, monIdx="..monIdx)
		if oneMon.pos then
			if bForce then
				freshSceneMonsterInPosForce( oneMon, fubenHandle )
			else
				freshSceneMonsterInPos( oneMon, fubenHandle )
			end
		elseif oneMon.range then
			if bForce then
				freshSceneMonsterInRangeForce( oneMon, fubenHandle )
			else
				freshSceneMonsterInRange( oneMon, fubenHandle )
			end
		end
	end
end

--野外boss被刷出
function BroadCommonBossMobMsg(monster, monId)
	--print("BroadCommonBossMobMsg, monId="..monId)
	local bossCfg = MobBossCommonConfig[monId]
	if bossCfg and bossCfg.mobMsg then
		local bossName = MonsterNameDeleteNumber(monId)			--BOSS名字，去掉数字
		System.broadcastTipmsg( string.format( bossCfg.mobMsg, bossName), ttScreenCenter + ttChatWindow)
	end
end

--野外boss被击杀
--sysarg:归属玩家
--lastHitKiller：最后一击玩家
function BroadCommonBossKillMsg( monster, Killer, monId, lastHitKiller )
	--print("BroadCommonBossKillMsg, monId="..monId)
	local bossCfg = MobBossCommonConfig[monId]
	if bossCfg and bossCfg.killMsg then
		local bossName = MonsterNameDeleteNumber(monId)			--BOSS名字，去掉数字
		System.broadcastTipmsg( string.format( bossCfg.killMsg, bossName, Actor.getName( Killer ) ), ttScreenCenter + ttChatWindow )
	end
end

function GetCommonBossKilledTime( bossId )
	local dVar = System.getDyanmicVar()
	if not dVar.bossKilledTime then
		dVar.bossKilledTime = {}
	end
	if not dVar.bossRevivalTimeRate then
		dVar.bossRevivalTimeRate = {}
	end
	local killTime = dVar.bossKilledTime[bossId] or 0
	--print("GetCommonBossKilledTime, killTime="..killTime)
	local revivalTimeRate =  dVar.bossRevivalTimeRate[bossId] or 1
	return killTime, revivalTimeRate
end

function SetCommonBossKilledTime( bossId, killTime )
	--print("SetCommonBossKilledTime, killTime="..killTime)
	local dVar = System.getDyanmicVar()
	if not dVar.bossKilledTime then
		dVar.bossKilledTime = {}
	end
	if not dVar.bossRevivalTimeRate then
		dVar.bossRevivalTimeRate = {}
	end
	dVar.bossKilledTime[bossId] = killTime
	local bossCfg = MobBossCommonConfig[bossId]
	if bossCfg and bossCfg.revivalTimeRate then
		dVar.bossRevivalTimeRate[bossId] = GetRevivalTimeRate()
	end
end

function GetCommonBossLastTime( bossId,  timeCd )
	local killTime = GetCommonBossKilledTime( bossId )
	local now = System.getCurrMiniTime()
	local lastTime = killTime + timeCd - now
	if lastTime < 0 then
		lastTime = 0
	end
	return lastTime
end

--[[
获取场景内BOSS和小怪数量
function GetCommonMonsterNumInScene( monsters, fubenHandle )
	fubenHandle = fubenHandle or 0
	local allBoss 		= 0
	local aliveBoss		= 0
	local allMon 		= 0
	local aliveMon 		= 0

	for idx, mon in ipairs( monsters ) do
		if idx == 1 then
			allBoss 	= allBoss + mon.num
			aliveBoss 	= aliveBoss + System.getMonsterCountById( mon.monsterId, mon.sceneId, fubenHandle )
		else
			allMon 		= allMon + mon.num
			aliveMon 	= aliveMon + System.getMonsterCountById( mon.monsterId, mon.sceneId, fubenHandle )
		end
	end

	return allBoss, allBoss-aliveBoss, allMon, allMon-aliveMon
end
]]

function GetCommonBossNum( fubenHandle, monsters )
	local bossTable = {}
	for monIdx, oneMon in ipairs( monsters ) do
		if oneMon.isBoss then
			--local bossName 	= MonsterNameDeleteNumber( oneMon.monsterId )
			local bossNum  	= oneMon.num
			local aliveNum	= System.getMonsterCountById( oneMon.monsterId, oneMon.sceneId, fubenHandle )
			local killNum 	= bossNum - aliveNum
			if killNum < 0 then
				killNum = 0
			end
			bossTable[oneMon.monsterId] = { killNum, bossNum }
		end
	end
	return bossTable
end

function GetCommonBossMonsterNum( sysarg, monsters )
	local fubenPtr 		= Actor.getFubenPrt(sysarg)
	local fubenHandle	= Fuben.getFubenHandle(fubenPtr)
	local allBoss 		= 0
	local aliveBoss		= 0
	local allMon 		= 0
	local aliveMon 		= 0

	for idx, mon in ipairs( monsters ) do
		if idx == 1 then
			allBoss 	= allBoss + mon.num
			aliveBoss 	= aliveBoss + System.getMonsterCountById( mon.monsterId, mon.sceneId, fubenHandle )
		else
			allMon 		= allMon + mon.num
			aliveMon 	= aliveMon + System.getMonsterCountById( mon.monsterId, mon.sceneId, fubenHandle )
		end
	end

	return allBoss, allBoss-aliveBoss, allMon, allMon-aliveMon
end

--[[
使用GetCommonBossMonsterNum6
function GetCommonBossMonsterNum2( sysarg, monsters )
	local fubenPtr 		= Actor.getFubenPrt(sysarg)
	local fubenHandle	= Fuben.getFubenHandle(fubenPtr)
	local allBoss 		= 0
	local aliveBoss		= 0
	local allMon 		= 0
	local aliveMon 		= 0

	for idx, mon in ipairs( monsters ) do
		if not mon.isFriend  then		--非本方的怪，算目标
			allMon 		= allMon + mon.num
			aliveMon 	= aliveMon + System.getMonsterCountById( mon.monsterId, mon.sceneId, fubenHandle )
		end
	end

	return allBoss, allBoss-aliveBoss, allMon, allMon-aliveMon
end
]]

--[[
统计怪物击杀、存活数量，合并重复的怪物，不存在算击杀
BOSS数量为0
一定要同场景
]]
function GetCommonBossMonsterNum3( fubenHandle, monsters, maxNum )
	if not maxNum then
		maxNum = 0
	end
	if #monsters <= 0 then
		return 0, 0, 0, 0
	end

	local allBoss 		= 0
	local aliveBoss		= 0
	local allMon 		= 0
	local aliveMon 		= 0

	--合并重复的monster
	local monstersTmp = {}
	for idx, mon in ipairs( monsters ) do
		local num = monstersTmp[mon.monsterId] or 0
		monstersTmp[mon.monsterId] = num + mon.num
	end

	local sceneId = monsters[1].sceneId
	for monsterId, monsterNum in pairs( monstersTmp  ) do
		allMon 		= allMon + monsterNum
		aliveMon 	= aliveMon + System.getMonsterCountById( monsterId, sceneId, fubenHandle )
	end
	if maxNum > 0 then			--怪物总
		allMon = maxNum
	end

	return allBoss, allBoss-aliveBoss, allMon, allMon-aliveMon
end

--[[
统计怪物击杀、存活数量，合并重复的怪物，不存在的怪的击杀数量算0
一定要同场景
]]
function GetCommonBossMonsterNum4( fubenHandle, monsters, maxNum, panelInfo )
	if #monsters <= 0 then
		return 0, 0, 0, 0
	end

	local allBoss 		= 0
	local aliveBoss		= 0
	local allMon 		= 0
	local aliveMon 		= 0

	--合并重复的monster
	local monstersTmp = {}
	for idx, mon in ipairs( monsters ) do
		local num = monstersTmp[mon.monsterId] or 0
		monstersTmp[mon.monsterId] = num + mon.num
	end

	local sceneId = monsters[1].sceneId
	for monsterId, monsterNum in pairs( monstersTmp  ) do
		allMon 		= allMon + monsterNum
	end
	return allBoss, 0, allMon, 0
end


--[[
适用于：没有BOSS只有小怪
]]
function GetCommonBossMonsterNum5( fubenHandle )
	--print("GetCommonBossMonsterNum5...")
	local fubenPtr = Fuben.getFubenPtr( fubenHandle )
	if not fubenPtr then
		return 0, 0, 0, 0
	end

	local allBoss 	= 0
	local killBoss	= 0
	local allMon	= Fuben.getFbMonsterTotal( fubenPtr )					--全部怪物
	local killMon 	= Fuben.getKillMonsterCount( fubenPtr ) 				--副本击杀怪物数量
	--print("GetCommonBossMonsterNum5, allMon="..allMon..", killMon="..killMon)

	return allBoss, killBoss, allMon, killMon
end

--[[
可以支持多个BOSS
noCount：true-不统计数量，false或无-统计数量
isBoss：true-BOSS，false或无-小怪
]]
function GetCommonBossMonsterNum6( fubenHandle, monsters )
	if #monsters <= 0 then
		return 0, 0, 0, 0
	end

	local allBoss 		= 0
	local aliveBoss		= 0
	local allMon 		= 0
	local aliveMon 		= 0

	--合并重复的monster
	local monstersTmp = {}
	for idx, mon in ipairs( monsters ) do
		if not mon.noCount then 			--此怪需要被统计在内
			if mon.isBoss then				--BOSS
				allBoss  = allBoss + mon.num
				aliveBoss= aliveBoss + System.getMonsterCountById( mon.monsterId, mon.sceneId, fubenHandle )
			else 							--小怪
				allMon   = allMon + mon.num
				aliveMon = aliveMon + System.getMonsterCountById( mon.monsterId, mon.sceneId, fubenHandle )
			end
		end
	end
	--print("GetCommonBossMonsterNum6, allBoss="..allBoss..", aliveBoss="..aliveBoss..", allMon="..allMon..", aliveMon="..aliveMon)
	return allBoss, allBoss-aliveBoss, allMon, allMon-aliveMon
end



--判断能否采集，可以采集返回true
function OnGatherMonster( sysarg, pGathMonster )
	local monId = Actor.getIntProperty(pGathMonster, PROP_ENTITY_ID)    --怪物ID
  	return GatherMonsterDispatcher.dispatch(sysarg, pGathMonster, monId)
end


--------------------------------------BOSS伤害排行榜------------begin-------------------------------------------------------
--[[
清空排行榜数据
]]
function ClearCommonBossHurtRank( bossPtr )
	--print("ClearCommonBossHurtRank...")
	local ranking = Ranking.getRankOfMonster( bossPtr )			--获取该BOSS的排行榜
	if ranking then
		Ranking.clearRanking(ranking)
	end
end

--通知客户端关闭伤害排行榜面板
function CloseCommonBossHurtRankPanel(sysarg, bossId)
	--print("CloseActiveBossHurtRankPanel...")
	local npack = DataPack.allocPacket(sysarg, enDefaultEntitySystemID, sSendCommonBossHurtRankData)
	if npack then
		DataPack.writeShort(npack, bossId)
		DataPack.writeChar(npack, 0)				--活动状态（0-关闭，1-进行）
		DataPack.flush(npack)
	end
end

--下发活动boss的伤害排行榜数据
function SendCommonBossHurtRankData(sysarg, bossPtr, lastTime, lastKiller)
	--print("SendCommonBossHurtRankData...")
	local bossId 		= Actor.getIntProperty(bossPtr, PROP_ENTITY_ID)
	local bossHurtCfg 	= CommonBossHurtAwardCfg[bossId]			--BOSS伤害配置
	if not bossHurtCfg then
		return
	end

	local ranking 	= Ranking.getRankOfMonster( bossPtr )			--获取该BOSS的排行榜
	if not ranking then
		local tips = string.format("rank not found, please insure that in \'data/config/monster/StdMonster.txt\' \'bCreateRank = true\' where entityid=%d",Actor.getIntProperty( sysarg, PROP_ENTITY_ID )); 
		System.trace(tips);
		return
	end

	local myId = Actor.getActorId(sysarg)
	local myDamage 	= 0
	local myIdx 	= 0
	local item = Ranking.getItemPtrFromId( ranking, myId)
	if item then
		myDamage = Ranking.getPoint(item) or 0
		if myDamage < bossHurtCfg.rankLimit then			--未上榜
			myIdx = 0
		else
			myIdx = Ranking.getIndexFromPtr(item) + 1
		end
	end

	--print("SendCommonBossHurtRankData, myId="..myId..", myIdx="..myIdx..", myDamage="..myDamage)
	if bossHurtCfg.displayLimit and myDamage < bossHurtCfg.displayLimit then		--伤害小于一定数值，不显示面板，不通知消息
		return
	end 

	local npack = DataPack.allocPacket(sysarg, enDefaultEntitySystemID, sSendCommonBossHurtRankData)
	if not npack then
		return
	end

	DataPack.writeShort(npack, bossId)
	DataPack.writeChar(npack, 1)				--活动状态（0-关闭，1-进行）
	DataPack.writeUInt(npack, lastTime)			--活动剩余时间

	DataPack.writeShort(npack, myIdx)		--本人名次
	DataPack.writeUInt(npack, myDamage)		--本人伤害
	--print("SendActiveBossHurtRankData, myIdx="..myIdx..", myDamage="..myDamage)
	local nCount = Ranking.getRankItemCountByLimit(ranking, bossHurtCfg.rankLimit)
	if nCount > bossHurtCfg.displayNum then
		nCount = bossHurtCfg.displayNum
	end
	DataPack.writeChar(npack, nCount)
	for idx=1, nCount do
		local rankItem = Ranking.getItemFromIndex(ranking, idx-1)
		if rankItem then
			local actorDamage	= Ranking.getPoint(rankItem)
			local actorId 		= Ranking.getId(rankItem)
			local actorName		= Ranking.getSub(rankItem, 0)
			DataPack.writeShort(npack, idx)
			DataPack.writeUInt(npack, actorId)
			DataPack.writeString(npack, actorName)
			DataPack.writeUInt(npack, actorDamage)
			--print("SendCommonBossHurtRankData,actorName="..actorName..", actorDamage="..actorDamage)
		end
	end
	DataPack.flush(npack)
	--print("SendActiveBossHurtRankData,send (139,13)")
end


function SendCommonBossHurtRankAward( bossPtr, killerId)
	local bossId 		= Actor.getIntProperty(bossPtr, PROP_ENTITY_ID)
	local bossHurtCfg 	= CommonBossHurtAwardCfg[bossId]			--BOSS伤害配置
	if not bossHurtCfg then
		return
	end
	--print("SendCommonBossHurtRankAward bossId="..bossId..", bossHurtCfg.bossId="..bossHurtCfg.bossId)

	local ranking 	= Ranking.getRankOfMonster( bossPtr )			--获取该BOSS的排行榜
	if not ranking then
		local tips = string.format("rank not found, please insure that in \'data/config/monster/StdMonster.txt\' \'bCreateRank = true\' where entityid=%d",cfg.entityId); 
		System.trace(tips);
		return
	end

	local  bossName = Actor.getName( bossPtr )
	local nCount = Ranking.getRankItemCountByLimit(ranking, bossHurtCfg.rankLimit)
	for idx=1, nCount do
		local rankItem = Ranking.getItemFromIndex(ranking, idx-1)
		if rankItem then
			local actorDamage	= Ranking.getPoint(rankItem)
			local actorId 		= Ranking.getId(rankItem)
			--满足最低伤害要求，可以发排行奖励和参与奖励
			if actorDamage >= bossHurtCfg.rankLimit then
				if bossHurtCfg.rankAward then 		--排名奖励
					MailCommonBossHurtAward( actorId, bossName, actorDamage, idx, bossHurtCfg.rankAward, bossHurtCfg.mailMsg.rankAwardMsg)
				end

				if bossHurtCfg.joinAward then			--参与奖励
					MailCommonBossJoinAward( actorId, bossName, bossHurtCfg.joinAward, bossHurtCfg.joinAwardMsg )
				end
			end
		end
	end

	--发送最后一击奖励
	if killerId and bossHurtCfg.killAward then
		MailCommonBossKillAward( killerId, bossName, bossCfg.bossAward.killAward, bossCfg.mailMsg.killAwardMsg  )
	end
end

--发送伤害排行奖励
function MailCommonBossHurtAward( actorId, bossName, damage, rankIdx, rankAwards, mailMsg )
	for i, rankAward in ipairs(rankAwards) do
		if rankAward.rankIdx[1] <= rankIdx and rankIdx <= rankAward.rankIdx[2] then
			local title 	= mailMsg.title
			local content 	= string.format(mailMsg.content, bossName, damage, rankIdx)
			Awards.GiveToMailById(actorId, {rankAward.award}, title, content, GameLog.clGuildBossHurtAward, Lang.ScriptTips.GuildLog005 )
			--print("MailCommonBossHurtAward， award.id="..rankAward.award.id)
			return
		end
	end
end

--发送最后一击奖励
function MailCommonBossKillAward( actorId, bossName, killAward, mailMsg )
	local title 	= mailMsg.title
	local content 	= string.format(mailMsg.content, bossName)
	Awards.GiveToMailById(actorId, {killAward}, title, content, GameLog.clGuildBossLastKillAward, Lang.ScriptTips.GuildLog007 )
end

--发送参与奖励
function MailCommonBossJoinAward( actorId, bossName, JoinAward, mailMsg)
	local title 	= mailMsg.title
	local content 	= string.format(mailMsg.content,bossName)
	Awards.GiveToMailById(actorId, {JoinAward}, title, content, GameLog.clGuildBossJoinAward, Lang.ScriptTips.GuildLog006 )
end
--------------------------------------BOSS伤害排行榜------------end---------------------------------------------------------

--[[
BOSS遭到伤害
bHurtTriggerScript:配置为true，该配置与bCreateRank没有关系
]]
function OnCommonBossHurted( sysarg, bossPtr, hurtValue )
	--print("OnCommonBossHurted, hurtValue="..hurtValue)
	OnBossBattleFieldBossHurted( sysarg, bossPtr, hurtValue )

	local fubenId = Actor.getFubenId( sysarg )
	if IsInKongFuMasterFuben( fubenId ) then
		OnKongFuMasterHurted( sysarg, bossPtr, hurtValue )
	end
end


--[[
获取BOSS的复活时间
BOSS、墓碑怪的ID必须唯一，且1对1
返回值：0：BOSS已经刷出，大于0：复活时间
]]
function GetCommonBossReliveTime(sceneId, fubenHandle, bossId)
	local bossCfg = MobBossCommonConfig[bossId]
	if not bossCfg then
		return 0
	end

	if not bossCfg.deadMonsterId then
		return 0
	end

	local bossNum = System.getMonsterCountById( bossId, sceneId, fubenHandle )
	if bossNum > 0 then
		return 0
	end

	local hScene = Fuben.getSceneHandleById( sceneId, fubenHandle )
	local bossPtr = Fuben.getMonsterPtrById( hScene, bossCfg.deadMonsterId )
	if not bossPtr then
		return 0
	end
	local reliveTime = Actor.getIntProperty(bossPtr, PROP_MONSTER_LIVE_TIMEOUT)		--怪物生命到期时间
	return reliveTime
end

--[[
墓碑怪生命到期
]]
function OnCommonBossDeadMonsterTimeout( deadMonsterPtr, deadMonsterId)
	local bossId = Actor.getOtherMonsterId( deadMonsterPtr ) 		--墓碑怪所属的BOSS
	--print("OnCommonBossDeadMonsterTimeout, deadMonsterId="..deadMonsterId..", bossId="..bossId)
	local bossCfg = MobBossCommonConfig[bossId]
	if bossCfg then
		local bossPtr = freshSceneOneMonsterInPos( bossCfg )
		if not bossPtr then
			--刷BOSS失败
			System.sendCommonLog( GameLog.clCommonBossRefreshFail, bossId, "" , 0, deadMonsterId, bossId, '', 'boss fail', '' )
		end
	else
		--没有BOSS，bossId有误
		System.sendCommonLog( GameLog.clCommonBossRefreshFail, bossId, "" , 0, deadMonsterId, bossId, '', 'no boss', '' )
	end
end

function GetCommonBossCfgByDeadMonsterId( deadMonsterId )
	if not deadMonsterId or deadMonsterId <= 0 then
		return nil
	end 
	for bossId, bossCfg in pairs( MobBossCommonConfig ) do
		if bossCfg.deadMonsterId and bossCfg.deadMonsterId == deadMonsterId then   --BOSS存在墓碑怪，需要循环刷新的
			return bossCfg
		end
	end
	return nil
end

--[[
仅BOSS使用，注意与OnCommonBossDie()是不同的
OnCommonBossDeath()一定会触发
]]
function OnCommonBossDeath( bossPtr, bossId )
	--print("OnCommonBossDeath, bossId="..bossId)
	ProcCommonBossRevival(bossPtr, bossId)
	MobCommonDeadMonster( bossPtr, bossId )
	SetCommonBossSceneStatus( bossId, 3 )		--设置为已击杀（如果有需要）
end


---------------------------------------------------------------------------------------------------------------------------
--[[
注册CommonFreshConfig中的怪物的处理时间
mobFunc     需要注册出现触发（缺省nil）
dieFunc     需要注册击杀触发（缺省nil）（有击杀者信息）
deathFunc   需要注册怪物死亡触发（缺省nil）（没有击杀者信息）
timeOutFunc   需要注册生命期触发（缺省nil）
]]
function CommonFreshRegisterMonsterFunc( freshIdx, mobFunc, dieFunc, deathFunc, timeOutFunc )
  --print("CommonFreshRegisterMonsterFunc .. freshIdx= "..freshIdx)
  local freshCfg = CommonFreshConfig[freshIdx]
  if not freshCfg then
    --print("can`t find config..")
    return
  end
  --print("CommonFreshRegisterMonsterFunc proc functions..")
  if  mobFunc then
    for i, freshMon in ipairs( freshCfg.freshMonsters ) do
      for i,oneMon in ipairs( freshMon.monsters ) do
        --print("mob monsterId= "..oneMon.monsterId)
        MonMobDispatcher.register( oneMon.monsterId, mobFunc )
      end
    end
  end

  if  dieFunc then
    for i, freshMon in ipairs( freshCfg.freshMonsters ) do
      for i,oneMon in ipairs( freshMon.monsters ) do
        --print("die monsterId= "..oneMon.monsterId)
        MonDieDispatcher.register( oneMon.monsterId, dieFunc )
      end
    end
  end

  if  deathFunc then
    for i, freshMon in ipairs( freshCfg.freshMonsters ) do
      for i,oneMon in ipairs( freshMon.monsters ) do
        MonDeathDispatcher.register( oneMon.monsterId, deathFunc )
      end
    end
  end

  if  timeOutFunc then
    for i, freshMon in ipairs( freshCfg.freshMonsters ) do
      for i,oneMon in ipairs( freshMon.monsters ) do
        MonLiveTimeOutDispatcher.register( oneMon.monsterId, timeOutFunc )
      end
    end
  end
end

--[[根据idx刷怪]]
function CommonFreshByFreshIdx( freshIdx, fubenHandle )
  --print("CommonFreshByFreshIdx.. ")
  local freshCfg = CommonFreshConfig[freshIdx]
  if not freshCfg then
    return
  end

  local freshMonCfg = GetElemByOpenServerDay( freshCfg.freshMonsters )
  if freshMonCfg then
       FreshCommonMonsters( freshMonCfg.monsters, fubenHandle, freshCfg.force )
  end
end

--[[
广播boss事件信息
type： 1：mob  2：die
]]
function CommonBossBroadcastBossEvent( type, monId, lastHitKiller, mobFormatDesc, dieFormatDesc  )   
    local bossName = System.getMonsterNameById(monId)           --BOSS名字，去掉数字
    if not bossName then
        return
    end
    if type == 1 then
        System.broadcastTipmsg( string.format( mobFormatDesc, bossName), ttScreenCenter + ttChatWindow)
    else
        if not lastHitKiller then
            return
        end
        System.broadcastTipmsg( string.format( dieFormatDesc, bossName, Actor.getName( lastHitKiller)), ttScreenCenter + ttChatWindow )
    end 
end

---------------------------------------------------------------------------------------------------------------------------
--FreshCommonBossWhenStart()			--引擎启动时刷出BOSS（这里，当@rsf时会执行一次）

